// biblix-mainlib.cs
//
//  Copyright (C) 2007 BOUTRY Arnaud arnaud@lordphoenix.info
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation; 
// 
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
//
using System;
using System.IO;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
namespace biblix
{
	public enum booksearchcriteria :int
	{
		titre,
		author,
		genre,
		serie,
		read,
		note,
		pret
	}
	
	public class booklist
	{ 
		private int _lastid; //To save last id used to add a book in list;
		private XmlDocument docbase;
		private string basefile;
		public booklist(string _basefile)
		{
			if( File.Exists(_basefile))
			{
				basefile = _basefile;
				docbase = new XmlDocument();
				docbase.Load(basefile);
				_lastid = int.Parse((docbase.DocumentElement.FirstChild as XmlElement).GetAttribute("lastid"));
			}
			else 
			{
				//Création du fichier XML de base de données.
				this.basefile = _basefile;
				if (!Directory.Exists(Path.GetDirectoryName(_basefile)))
					Directory.CreateDirectory(Path.GetDirectoryName(_basefile));
				docbase = new XmlDocument();
				docbase.LoadXml("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?> <booklist></booklist>");
				XmlElement infonode = docbase.CreateElement("info");
				infonode.SetAttribute("lastid","0");
				_lastid=0;
				docbase.DocumentElement.AppendChild(infonode);
				docbase.Save(basefile);
			}
		}
		
		private void setlastid(int id)
		{
			(docbase.DocumentElement.FirstChild as XmlElement).SetAttribute("lastid",id.ToString());
		}
		
		private void save()
		{
			docbase.Save(basefile);
		}
		public ArrayList getBooklist()
		{
			ArrayList resultlist = new ArrayList();
			XmlNodeList list = docbase.GetElementsByTagName("book");
			IEnumerator i = list.GetEnumerator();
			while(i.MoveNext())
			{
				XmlElement currentbooknode= (XmlElement)i.Current;
				book _book = new book();
				_book.auteur = currentbooknode.SelectSingleNode("/auteur").Value;
				_book.titre  = currentbooknode.SelectSingleNode("/titre").Value;
				resultlist.Add(_book);
			}
			return resultlist;
		}
		
		public ArrayList getidlist()
		{
			ArrayList result = new ArrayList();
			XmlNodeList list = docbase.GetElementsByTagName("book");
			IEnumerator i = list.GetEnumerator();
			while(i.MoveNext())
			{
				string id = (i.Current as XmlElement).GetAttribute("id");
				result.Add(id);
			}
			return result;
		}
		
		public bool addbook(book item)
		{
			bool result = false; 
			XmlElement booknode = docbase.CreateElement("book");
			_lastid = _lastid+1;
			booknode.SetAttribute("id",_lastid.ToString());
			item.CreateXMLInfoNode(booknode);
			docbase.DocumentElement.AppendChild(booknode);
			setlastid(_lastid);
			this.save();
			result = true;
			return result;
		}
		
		public bool deletebook(string id)
		{
			bool result;
			XmlNode booknode = docbase.SelectSingleNode(String.Format("//book[@id=\"{0}\"]",id));
			if (booknode!=null)
			{
				booknode.ParentNode.RemoveChild(booknode);
				save();
				result=true;
			}
			else
				result = false;
			return result;
			
		}
		public void updatebook(book workbook)
		{
			XmlNode booknode = docbase.SelectSingleNode(String.Format("//book[@id=\"{0}\"]",workbook.id));
			booknode.RemoveAll();
			System.Xml.XmlAttribute idnode = docbase.CreateAttribute("id");
			idnode.Value=workbook.id;
			booknode.Attributes.Append(idnode);
			workbook.CreateXMLInfoNode((XmlElement)booknode);
			save();
		}
		
		public book getbook(string id)
		{
			book workbook = new book();
			workbook.id = id;
			XmlNode booknode = docbase.DocumentElement.SelectSingleNode(String.Format("//book[@id='{0}']",id));
			if (booknode!=null)
				workbook.extractXML(booknode);
			return workbook;
		}
		
		public ArrayList SearchBook(biblix.booksearchcriteria criteria,string value)
		{
			string xpathquery ="";
			ArrayList idlist = new ArrayList();
			string nodename=string.Empty;
			switch (criteria)
			{
			case biblix.booksearchcriteria.author:
				nodename="auteur";
				break;
			case biblix.booksearchcriteria.titre :
				nodename="titre";
				break;
			case biblix.booksearchcriteria.genre :
				nodename="genre";
				break;
			case biblix.booksearchcriteria.read : 
				nodename="lu";
				break;
			case biblix.booksearchcriteria.serie : 
				nodename="serie";
				break;
			case biblix.booksearchcriteria.pret : 
				nodename="pret";
				break;
			case biblix.booksearchcriteria.note : 
				nodename="note";
				break;
			}
			xpathquery=String.Format("//book[{0}='{1}']",nodename,value);
			XmlNodeList booklist = docbase.DocumentElement.SelectNodes(xpathquery);
			IEnumerator i = booklist.GetEnumerator();
			while(i.MoveNext())
				idlist.Add((i.Current as XmlElement).GetAttribute("id"));
			return idlist;
		}
		
		public ArrayList SearchBook(biblix.booksearchcriteria criteria,bool searchvalue)
		{
			ArrayList idlist = new ArrayList();
			string searchstring=String.Empty;
			if (searchvalue)
				searchstring="O";
			else
				searchstring="N";
			idlist = SearchBook(criteria,searchstring);
			return idlist;
		}
		
		public ArrayList SearchBook(biblix.booksearchcriteria criteria,int searchvalue)
		{
			ArrayList idlist = new ArrayList();
			string searchstring=searchvalue.ToString();
			idlist = SearchBook(criteria,searchstring);
			return idlist;
		}
		
		private ArrayList GetMetaValueList(string nodename)
		{
			ArrayList valuelist = new ArrayList();
			string xpathquery=String.Format("//{0}",nodename);
			XmlNodeList nodelist = docbase.DocumentElement.SelectNodes(xpathquery);
			foreach(XmlElement node in nodelist)
			{
				if (!valuelist.Contains(node.InnerText))
					valuelist.Add(node.InnerText);
			}
			return valuelist;
		}
		
		public ArrayList GetGenreList()
		{
			ArrayList genrelist = new ArrayList();
			genrelist = this.GetMetaValueList("genre");
			return genrelist;
		}
		
		public ArrayList GetAuthorList()
		{
			ArrayList authorlist = this.GetMetaValueList("auteur");
			return authorlist;
		}
		
		public ArrayList GetSourcesList()
		{
			ArrayList sourcelist = this.GetMetaValueList("source");
			return sourcelist;
		}
		
		public ArrayList getReadBook(bool read)
		{
			ArrayList readbook = new ArrayList();
			string searchvalue=string.Empty;
			if (read)
				searchvalue="O";
			else 
				searchvalue ="N";
			readbook = SearchBook(biblix.booksearchcriteria.read,searchvalue);
			return readbook;
		}

	}
	public class book : Object, ICloneable
	{
		private string _id;
		private string _titre;
		private string _auteur;
		private int _note;
		private string _serie;
		private int _volume;
		private string _genre;
		private bool _lu;
		private bool _pret;
		private string _commentaire;
		private string _resume;
		private string _publishyear;
		private DateTime _statedate; 
		private string _source; 
		
		public book(string titre,string auteur)
		{
			_titre=titre;
			_auteur=auteur;
			_note = -1;
			_volume = -1;
		}
		
		public book()
		{
			_titre="";
			_auteur="";
			_note=-1;
			_volume =0;
			_lu = false;
		}
		
		public object Clone()
		{
			book result = new book();
			result._auteur = _auteur;
			result._commentaire=_commentaire;
			result._genre= _genre;
			result._id = _id;
			result._lu = _lu;
			result._note = _note;
			result._pret=_pret;
			result._publishyear = _publishyear;
			result._resume = _resume;
			result._serie = _serie;
			result._source = _source;
			result._statedate = _statedate;
			result._titre = _titre;
			result._volume = _volume;
			return result;
		}
		
		public void extractXML(XmlNode parentnode) //Extract value in XMLNode and save it in coorect field of current book object
		{
			XmlNode idnode = parentnode.Attributes.GetNamedItem("id");
			this.id =idnode.Value;
			IEnumerator i = parentnode.ChildNodes.GetEnumerator();
			while(i.MoveNext())
			{
				XmlNode node = (XmlNode)i.Current;
				if (node.Name=="titre")
					this.titre = node.InnerText;
				if (node.Name=="auteur")
					this.auteur = node.InnerText;
				if (node.Name=="genre")
					this.genre = node.InnerText;
				if(node.Name=="serie")
					serie=node.InnerText;
				if (node.Name=="parution")
					this.publishyear=node.InnerText;
				if (node.Name=="volume")
					volume=Int32.Parse(node.InnerText);
				if(node.Name=="note")
					note=Int32.Parse(node.InnerText);
				if(node.Name=="source")
					source=node.InnerText;
				if(node.Name=="date")
					shortdate=node.InnerText;
				if(node.Name=="lu")
				{
					if((node.InnerText=="N")|(node.InnerText=="n"))
						lu=false;
					if ((node.InnerText=="O")|(node.InnerText=="O"))
						lu=true;
				}
				if(node.Name=="pret")
				{
					if((node.InnerText=="N")|(node.InnerText=="n"))
						pret=false;
					if((node.InnerText=="O")|(node.InnerText=="O"))
						pret=true;
				}
				if(node.Name=="comment")
					commentaire = (node.FirstChild as XmlCDataSection).Data; 
				if (node.Name=="synopsis")
					resume=(node.FirstChild as XmlCDataSection).Data;
			}
		}
		
		public void CreateXMLInfoNode(XmlElement booknode)
		{
			XmlElement infonode;
			XmlText textnode;
			XmlDocument doc = booknode.OwnerDocument;
			
			if (!String.IsNullOrEmpty(titre))
			{
				infonode = doc.CreateElement("titre");
				textnode =doc.CreateTextNode(titre);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			if (!String.IsNullOrEmpty(auteur))
			{
				infonode = doc.CreateElement("auteur");
				textnode =doc.CreateTextNode(auteur);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			if (!String.IsNullOrEmpty(genre))
			{
				infonode = doc.CreateElement("genre");
				textnode = doc.CreateTextNode(genre);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			if (note!=-1)
			{
				infonode = doc.CreateElement("note");
				textnode = doc.CreateTextNode(note.ToString());
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			if(volume!=0)
			{
				infonode = doc.CreateElement("volume");
				textnode = doc.CreateTextNode(volume.ToString());
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
				
			if (shortdate!="01/01/0001")
			{
				infonode = doc.CreateElement("date");
				textnode = doc.CreateTextNode(this.shortdate);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			if (!String.IsNullOrEmpty(publishyear))
			{
				infonode = doc.CreateElement("parution");
				textnode = doc.CreateTextNode(publishyear);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			
			if (!String.IsNullOrEmpty(source))
			{
				infonode=doc.CreateElement("source");
				textnode = doc.CreateTextNode(source);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			
			if(!String.IsNullOrEmpty(serie))
			{
				infonode = doc.CreateElement("serie");
				textnode = doc.CreateTextNode(serie);
				infonode.AppendChild(textnode);
				booknode.AppendChild(infonode);
			}
			
			if(!String.IsNullOrEmpty(resume))
			{
				infonode=doc.CreateElement("synopsis");
				XmlCDataSection datanode = doc.CreateCDataSection(resume);
				infonode.AppendChild(datanode);
				booknode.AppendChild(infonode);
			}
			
			if (!String.IsNullOrEmpty(commentaire))
			{
				infonode = doc.CreateElement("comment");
				XmlCDataSection datanode = doc.CreateCDataSection(commentaire);
				infonode.AppendChild(datanode);
				booknode.AppendChild(infonode);
			}
			
			infonode =doc.CreateElement("lu");
			if (lu)
				textnode = doc.CreateTextNode("O");
			else
				textnode = doc.CreateTextNode("N");
			infonode.AppendChild(textnode);
			booknode.AppendChild(infonode);
			
			infonode = doc.CreateElement("pret");
			if(pret)
				textnode = doc.CreateTextNode("O");
			else
				textnode= doc.CreateTextNode("N");
			infonode.AppendChild(textnode);
			booknode.AppendChild(infonode);
		}
		
		public string id
		{
			get{return _id;}
			set{_id= value;}
		}
		public string titre
		{
			get{return _titre;}
			set{_titre = value;}
		}
		
		public string auteur
		{
			get{return _auteur;}
			set{_auteur= value;}
		}
		
		public int note
		{
			get{return _note;}
			set
			{
				if (value<-1)
					_note=-1;
				else 
				{
					if (value>5)
						_note=5;
					else 
						_note = value;
				}
			}
		}
		public bool lu
		{
			get{return _lu;}
			set{_lu = value;}
		}
		public string genre
		{
			get{return _genre;}
			set{_genre = value;}
		}
		public string serie
		{
			get{return _serie;}
			set{_serie=value;}
		}
		public int volume
		{
			get{return _volume;}
			set{_volume = value;}
		}
		public string commentaire
		{
			get{return _commentaire;}
			set{_commentaire=value;}
		}
		public string resume
		{
			get{return _resume;}
			set{_resume = value;}
		}
		
		public string publishyear
		{
			get{return _publishyear;}
			set{_publishyear = value;}
		}
		
		public string shortdate
		{
			get{return _statedate.ToShortDateString();}
			set{
				string strdate = value;
				int year,month,day;
				day = Int32.Parse(strdate.Substring(0,2));
				month = Int32.Parse(strdate.Substring(3,2));
				year = Int32.Parse(strdate.Substring(6,4));
				_statedate = new DateTime(year,month,day);
				
			}
		}

		public string longdate
		{
			get{return _statedate.ToLongDateString();}
		}
		
		public DateTime date
		{
			get{return _statedate;}
			set{_statedate=value;}
		}
		
		public string source
		{
			get {return _source;}
			set {_source=value;}
		}
		
		public bool pret
		{
			get {return _pret;}
			set {_pret=value;}
		}
	}
}




